package org.ysh.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.ysh.core.utils.ShiroUtils;
import org.ysh.core.utils.StringUtils;
import org.ysh.domain.Resource;
import org.ysh.mapper.ResourceMapper;
import org.ysh.vo.IndexInfoVo;

import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;

@Service
@Slf4j
public class ResourceService extends BaseService<Integer, Resource>{

    public ResourceService(ResourceMapper mapper) {
        super(mapper);
    }

    /**
     * 根据资源编码查询资源信息
     * @param code
     * @return
     */
    public Resource findByResourceCode(String code) {
        Resource resource = new Resource();
        resource.setResourceCode(code);
        List<Resource> list = findByPage(resource);
        return list.isEmpty()? null : list.get(0);
    }

    public List<Resource> findByUser(Integer userId) {
        return ((ResourceMapper)baseMapper).findByUser(userId);
    }

    /**
     * 保存资源信息
     * @param resources
     */
    public void save(List<Resource> resources){
        if(resources == null) {
            throw new RuntimeException("资源信息不能为空");
        }
        Queue<Resource> queue = new LinkedBlockingQueue<>(resources);
        while(!queue.isEmpty()){
            Resource resource = queue.poll();

            // 默认为顶级资源
            if(StringUtils.isEmpty(resource.getParentCode())) {
                resource.setLevel(1);
                insertOrUpdate(resource);
                continue;
            }

            //如果不是一级资源
            // 递归查询父资源
            Resource parentResource = this.findByResourceCode(resource.getParentCode());

            if(parentResource != null) {
                resource.setLevel(parentResource.getLevel() + 1);
                insertOrUpdate(resource);
                continue;
            }

            parentResource = this.findParentResource(resource.getParentCode(),resources);
            if(parentResource!= null) {
                queue.add(resource);//把它重新加入到列表队尾
                log.info("资源编码为{}的父资源信息不存在，将其加入到列表队尾",resource.getResourceCode());
                continue;
            }

            throw new RuntimeException("父资源信息不存在");

        }
    }

    private Resource findParentResource(String resourceCode, List<Resource> resources) {
        for (Resource resource : resources) {
            if(resource.getResourceCode().equals(resourceCode)){
                return resource;
            }
        }
        return null;
    }

    public void insertOrUpdate(Resource resource){
        if(resource == null) {
            throw new RuntimeException("资源信息不能为空");
        }
        if(StringUtils.isEmpty(resource.getResourceCode())) {
            throw new RuntimeException("资源编码不能为空");
        }

        Resource storedResource = findByResourceCode(resource.getResourceCode());

        if(storedResource != null){
            resource.setId(storedResource.getId());
            resource.setUpdateTime(new Date());
            resource.setUpdateBy(1);
            update(resource);
        }else{
            resource.setCreateBy(1);
            resource.setCreateTime(new Date());
            insert(resource);
        }
    }


    public List<IndexInfoVo.MenuInfo> buildMenuInfos() {
        Resource resource = new Resource();
        resource.setType(Resource.RESOURCE_TYPE_MENU);
        List<Resource> resources;
        if("admin".equals(ShiroUtils.getCurrentUser().getUsername())){
            resources = findByPage(resource);
        }else{
            //获取当前的用户资源
            resources = findByUser(ShiroUtils.getCurrentUser().getId());
            resources.removeIf(res -> res.getType() != Resource.RESOURCE_TYPE_MENU);
        }
        return buildMenuInfos("",resources);
    }

    private List<IndexInfoVo.MenuInfo> buildMenuInfos(String parentCd,List<Resource> resources) {

        List<IndexInfoVo.MenuInfo> menus = new ArrayList<>();

        for (Resource resource : resources) {
            if(parentCd.equals(resource.getParentCode())) {
                IndexInfoVo.MenuInfo menuInfo = IndexInfoVo.buildMenuInfo(resource.getResourceName(),resource.getUrl(),resource.getIcon());
                menus.add(menuInfo);

                List<IndexInfoVo.MenuInfo> children = buildMenuInfos(resource.getResourceCode(),resources);

                if(!children.isEmpty()) {
                    menuInfo.setChild(children);
                }
            }
        }

        return menus;
    }
}
